import * as vscode from 'vscode';

/**
 * WebView通信辅助工具类
 * 提供更可靠的WebView消息发送和内容管理功能
 */
export class WebViewHelper {
    /**
     * 安全地向WebView发送消息，带有重试机制
     */
    public static sendMessageWithRetry(
        panel: vscode.WebviewPanel,
        message: any,
        retryCount: number = 3,
        retryDelayMs: number = 300
    ): Promise<boolean> {
        return new Promise<boolean>((resolve) => {
            const tryToSend = (attemptCount: number) => {
                try {
                    console.log("尝试发送WebView消息(尝试" + attemptCount + "/" + retryCount + "):" + message.command);
                    panel.webview.postMessage(message);
                    resolve(true);
                } catch (error) {
                    console.error("发送WebView消息失败(尝试" + attemptCount + "/" + retryCount + "):", error);
                    if (attemptCount < retryCount) {
                        setTimeout(() => tryToSend(attemptCount + 1), retryDelayMs);
                    } else {
                        console.error('发送WebView消息失败，已达到最大重试次数');
                        resolve(false);
                    }
                }
            };
            
            tryToSend(1);
        });
    }
    
    /**
     * 更新特定标签页的内容
     */
    public static async updateTabContent(
        panel: vscode.WebviewPanel,
        tabId: string,
        content: string,
        timeout: number = 1000
    ): Promise<boolean> {
        console.log("更新标签页内容: " + tabId + ", 内容长度: " + content.length);
        
        // 先尝试发送一个ping消息确认WebView准备就绪
        await this.sendMessageWithRetry(panel, { command: 'ping', timestamp: Date.now() });
        
        // 然后发送内容更新消息
        return this.sendMessageWithRetry(panel, {
            command: 'updateTab',
            tab: tabId,
            content: content
        }, 2, 500);
    }
    
    /**
     * 确保WebView已就绪并发送所有内容
     */
    public static ensureContentDelivery(
        panel: vscode.WebviewPanel,
        contents: Map<string, string | (() => string)>,
        timeout: number = 3000
    ): void {
        // 创建一个超时计时器，确保即使没有收到webviewReady消息也会发送内容
        const timeoutId = setTimeout(() => {
            console.log(`等待WebView就绪超时(${timeout}ms)，强制发送内容...`);
            this.deliverAllContents(panel, contents);
        }, timeout);
        
        // 监听一次性事件，当WebView报告就绪时
        const disposable = panel.webview.onDidReceiveMessage(async message => {
            if (message.command === 'webviewReady' || message.command === 'pageLoaded') {
                console.log('收到WebView就绪消息:', message.command);
                // 清除超时计时器
                clearTimeout(timeoutId);
                // 移除事件监听器
                disposable.dispose();
                // 发送所有内容
                await this.deliverAllContents(panel, contents);
            }
        });
    }
    
    /**
     * 增强版的确保WebView已就绪并发送所有内容
     * 增加了更多的安全检测和重试机制
     */
    public static ensureContentDeliveryEnhanced(
        panel: vscode.WebviewPanel,
        contents: Map<string, string | (() => string)>,
        timeout: number = 5000,
        maxRetries: number = 2
    ): void {
        console.log(`增强版WebView内容传递 - 超时: ${timeout}ms, 最大重试: ${maxRetries}次`);
        
        // 状态跟踪
        const deliveryState = {
            attemptCount: 0,
            hasReceivedReady: false,
            isDeliveryComplete: false
        };
        
        // 创建一个超时计时器
        const timeoutId = setTimeout(() => {
            if (!deliveryState.isDeliveryComplete) {
                console.log(`等待WebView就绪超时(${timeout}ms)，强制发送内容...尝试次数: ${deliveryState.attemptCount + 1}`);
                
                // 先发送ping测试WebView连接状态
                try {
                    panel.webview.postMessage({ command: 'ping', timestamp: Date.now() });
                    console.log('WebView ping已发送，开始发送内容');
                    this.deliverAllContentsEnhanced(panel, contents, deliveryState);
                } catch (err) {
                    console.warn('WebView ping发送失败:', err);
                    // 即使ping失败也尝试发送内容
                    this.deliverAllContentsEnhanced(panel, contents, deliveryState);
                }
            }
        }, timeout);
        
        // 监听一次性事件，当WebView报告就绪时
        const disposable = panel.webview.onDidReceiveMessage(async message => {
            if (message.command === 'webviewReady' || message.command === 'pageLoaded' || message.command === 'pong') {
                console.log('收到WebView消息:', message.command);
                
                if (!deliveryState.hasReceivedReady) {
                    deliveryState.hasReceivedReady = true;
                    
                    // 清除超时计时器
                    clearTimeout(timeoutId);
                    
                    // 发送所有内容
                    await this.deliverAllContentsEnhanced(panel, contents, deliveryState);
                    
                    // 移除事件监听器
                    if (deliveryState.isDeliveryComplete) {
                        disposable.dispose();
                    }
                }
            }
        });
        
        // 主动发送ping消息检查WebView是否准备好
        setTimeout(() => {
            console.log('发送ping消息检查WebView状态');
            try {
                panel.webview.postMessage({ command: 'ping', timestamp: Date.now() });
            } catch (err) {
                console.warn('发送ping失败:', err);
            }
        }, 500);  // 给WebView 500ms初始化的时间
    }
    
    /**
     * 发送所有内容到WebView
     */
    private static async deliverAllContents(
        panel: vscode.WebviewPanel,
        contents: Map<string, string | (() => string)>
    ): Promise<void> {
        console.log('开始发送所有内容到WebView...');
        
        for (const [tabId, contentOrFunction] of contents.entries()) {
            try {
                try {
                    // 尝试获取内容，处理生成内容可能的错误
                    let content;
                    try {
                        content = typeof contentOrFunction === 'function'
                            ? contentOrFunction()
                            : contentOrFunction;
                    } catch (contentError) {
                        console.error(`生成标签 ${tabId} 内容时出错:`, contentError);
                        content = `
                            <div class="content-error">
                                <h3>内容生成失败</h3>
                                <p>生成标签 ${tabId} 内容时发生错误</p>
                                <p>请尝试刷新页面</p>
                                <button onclick="vscode.postMessage({command: 'refresh'})">刷新</button>
                            </div>
                            <style>
                                .content-error {
                                    color: #e51400;
                                    padding: 15px;
                                    border: 1px solid #e51400;
                                    border-radius: 5px;
                                    margin: 20px 0;
                                }
                                .content-error button {
                                    background-color: var(--vscode-button-background);
                                    color: var(--vscode-button-foreground);
                                    border: none;
                                    padding: 6px 12px;
                                    margin-top: 10px;
                                    cursor: pointer;
                                }
                            </style>
                        `;
                    }
                    
                    // 使用延迟确保WebView有足够时间处理每个消息
                    await new Promise(resolve => setTimeout(resolve, 200));
                    await this.updateTabContent(panel, tabId, content);
                } catch (error) {
                    console.error(`发送标签 ${tabId} 内容时出错:`, error);
                }
            } catch (error) {
                console.error(`发送标签页 ${tabId} 内容时出错:`, error);
            }
        }
        
        console.log('所有内容已发送完毕');
    }
    
    /**
     * 增强版发送所有内容到WebView
     */
    private static async deliverAllContentsEnhanced(
        panel: vscode.WebviewPanel,
        contents: Map<string, string | (() => string)>,
        state: { attemptCount: number; hasReceivedReady: boolean; isDeliveryComplete: boolean }
    ): Promise<void> {
        console.log(`开始发送所有内容到WebView...尝试次数: ${++state.attemptCount}`);
        let successCount = 0;
        
        for (const [tabId, contentOrFunction] of contents.entries()) {
            try {
                let content: string;
                
                try {
                    // 使用包装函数处理每个内容生成的可能错误
                    content = typeof contentOrFunction === 'function'
                        ? this.safelyGenerateContent(contentOrFunction, tabId)
                        : contentOrFunction;
                } catch (contentError) {
                    console.error(`生成标签 ${tabId} 内容时出错:`, contentError);
                    content = this.generateErrorContent(tabId, contentError);
                }
                
                // 添加延迟以避免消息过于密集
                await new Promise(resolve => setTimeout(resolve, 300));
                
                // 发送内容，支持重试
                const success = await this.sendMessageWithRetry(panel, {
                    command: 'updateTab',
                    tab: tabId,
                    content: content
                }, 2, 500);
                
                if (success) {
                    console.log(`✓ 标签 ${tabId} 内容已成功发送`);
                    successCount++;
                } else {
                    console.error(`✗ 标签 ${tabId} 内容发送失败`);
                }
            } catch (error) {
                console.error(`发送标签页 ${tabId} 内容时出错:`, error);
            }
        }
        
        // 更新状态
        state.isDeliveryComplete = successCount === contents.size;
        
        console.log(`内容发送完成，成功: ${successCount}/${contents.size}`);
        
        // 如果有失败的标签且尝试次数未达到上限，则再次尝试
        if (!state.isDeliveryComplete && state.attemptCount < 3) {
            console.log(`将在2秒后重试发送失败的内容...`);
            setTimeout(() => this.deliverAllContentsEnhanced(panel, contents, state), 2000);
        }
    }
    
    /**
     * 安全地生成内容
     */
    private static safelyGenerateContent(generator: () => string, tabId: string): string {
        try {
            return generator();
        } catch (error) {
            console.error(`生成${tabId}内容时出错:`, error);
            return this.generateErrorContent(tabId, error);
        }
    }
    
    /**
     * 生成错误内容
     */
    private static generateErrorContent(tabId: string, error: unknown): string {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return `
            <div class="content-error">
                <h3>内容生成失败</h3>
                <p>生成标签 ${tabId} 内容时发生错误: ${errorMessage}</p>
                <p>请尝试刷新页面</p>
                <button onclick="vscode.postMessage({command: 'refresh'})">刷新</button>
            </div>
            <style>
                .content-error {
                    color: #e51400;
                    padding: 15px;
                    border: 1px solid #e51400;
                    border-radius: 5px;
                    margin: 20px 0;
                }
                .content-error button {
                    background-color: var(--vscode-button-background);
                    color: var(--vscode-button-foreground);
                    border: none;
                    padding: 6px 12px;
                    margin-top: 10px;
                    cursor: pointer;
                }
            </style>
        `;
    }
}